package neuronalenetzeelearning.model;

import java.util.Vector;

public class SupervisedLearningRule extends LearningRule {

    //gewünschtes (Lehr-)muster; ACHTUNG: muss Länge der(quadratischen)Matrix haben
    public static final double[] DEFAULT_WantedOutVectors = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    private Vector<Vector<Double>> WantedOutVectors;   //gewünschte Ausgabe-Vektoren
    

    //FIXME use super() and fix constructors
    public SupervisedLearningRule(Graph g, Vector<Vector<Double>> IV, Vector<Vector<Double>> OV, double lr, StepFunction stepFunction) {
        super(g, lr, stepFunction, IV);
        if(OV.size()!=IV.size()){
            System.out.println("OV.size()="+OV.size()+" IV.size()="+IV.size());
            System.out.println("<<<FEHLERMELDUNG: Anzahl der Ziel- und Eingabevektoren stimmt nicht übereein!>>>");
        }
        this.WantedOutVectors=OV;
   }

    @Override
    /*
     * Hat zZ keine Nutzung
     */
    public void getChangeWeight(Graph graph) {
        nextStep();
    }

    @Override
    public void nextStep() {
        super.setRandomInput();
        //welches Inputmuster?
        int inputLength = super.getGraph().getLayer1Nodes().size();
        int numberOfPattern=0; //index vom Vector possibleInputVectors
        for (int i=0; i<inputLength; i++){
            Node oi = getGraph().getLayer1Nodes().elementAt(i);
            double inputOi = oi.getInputValue();
            if (inputOi!=possibleInputVectors.elementAt(numberOfPattern).elementAt(i)){
                numberOfPattern++; //vergleiche vorliegendes Muster mit nächstem in possibleInputVectors
                i=-1;//das Muster muss mit dem nachfolgenden Muster vom ersten Index an verglichen werden
            }
        }
        for (int j = 0; j < getGraph().getLayer2Nodes().size(); j++) {
            Node oj = getGraph().getLayer2Nodes().elementAt(j);
            double outputOj = stepFunction.calculate(oj);
            double tj = this.WantedOutVectors.elementAt(numberOfPattern).elementAt(j);

            for (int k = 0; k < oj.getIncomingEdges().size(); k++) {
                Edge edge = oj.getIncomingEdges().elementAt(k);
                
                Node oi = oj.getIncomingEdges().elementAt(k).getFrom();
                double outputOi = stepFunction.calculate(oi);

                double oldWeight = oj.getIncomingEdges().elementAt(k).getWeight();
                double newWeight = oldWeight + this.learningRate * (tj - outputOj) * outputOi;
                edge.setWeight(newWeight);
            }
        }
        //Konsolenausgabe:
        System.out.print("\nEingabevektor: ");
        for(int i=0; i<getGraph().getLayer1Nodes().size(); i++){
           System.out.print(getGraph().getLayer1Nodes().get(i).getInputValue()+", ");
        }
        System.out.print("\nZielvektor: ");
        for(int i=0; i<getGraph().getLayer2Nodes().size(); i++){
            System.out.print(this.WantedOutVectors.elementAt(numberOfPattern).elementAt(i)+", ");
        }
        System.out.print("\nAusgabevektor: ");
        for(int i=0; i<getGraph().getLayer2Nodes().size(); i++){
           System.out.print(getGraph().getLayer2Nodes().get(i).getOutputValue()+", ");
        }
    }

    @Override
    /*
     * Wird in den Klassen LearningRule & PropertyController durch die Methode
     * RestrictedLearningIteration realisiert
     */
    public void nextStep(int anzahlDerWiederholungen) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
